#ifndef MOCHA_DETAIL_PLUGIN_PLATFORM_HPP_INCLUDED
#define MOCHA_DETAIL_PLUGIN_PLATFORM_HPP_INCLUDED

/**
 * @file
 */

#include <cstdint>
#include <map>
#include <string>
#include <vector>
#include <boost/filesystem.hpp>
#include <boost/noncopyable.hpp>
#include <boost/signal.hpp>
#include "mocha/plugin.hpp"
#include "mocha/pointers.hpp"

namespace mocha {
class object_importer;
/**
 * Loads and manages plugins and services.
 * Each factory can load a single binary. Currently, each binary must provide a working set of plugins.
 * A factory creates and clones plugin objects.
 */
class plugin_factory : public boost::noncopyable {
public:
	/// Signal fired when a factory closes its associated binary (all plugins loaded from that binary are invalidated).
	boost::signal<void(const plugin_factory* const)> closed;
	plugin_factory();
	~plugin_factory();
	/**
	 * Opens plugins specified by the local configuration.
	 */
	int open();
	/**
	 * Opens a plugin XML configuration file, loading that plugin and its dependencies.
	 * Reports an error if dependencies could not be found or loaded.
	 * @param file Plugin XML configuration file.
	 * @return Zero on success, otherwise non-zero.
	 */
	int open_xml(const boost::filesystem::path& file);
	/**
	 * Opens a binary file (shared object) and loads any plugins.
	 * @param file File to open.
	 * @return Zero on success, otherwise non-zero.
	 */
	int open_binary(const boost::filesystem::path& file);
	/**
	 * Closes the library and plugins.
	 * @return
	 */
	int close();
	/**
	 *
	 * @param type
	 * @param params
	 * @return
	 */
	int register_object(const std::string& type, const mocha_plugin_register_params* rp);
	/**
	 * Creates (instantiates) a plugin object.
	 * @param name Plugin type name of the plugin object.
	 * @param importer
	 * @return A plugin object if successful, otherwise null.
	 */
	void* create_object(const std::string& name, const object_importer& importer) const;
	/**
	 * Clones (copies) a plugin object.
	 * @param object
	 * @param importer
	 * @return A copy of a plugin object if successful, otherwise null. A null return may indicate that the plugin object is simply not copyable. Check the object parameters to verify.
	 */
	void* clone_object(const void* object, const object_importer& importer) const;
	/**
	 *
	 * @return
	 */
	int register_service(/*...*/);
	/**
	 *
	 * @param name
	 * @param params
	 * @return
	 */
	int invoke_service(const std::string& name, void* params);
	/**
	 *
	 * @return
	 */
	const mocha_plugin_factory_params* parameters() const;
private:
	typedef std::map<std::string, mocha_plugin_register_params> object_con_t;
	/**
	 * Invokes a remote plugin initialization function. The remote function should register any plugins.
	 * @param init Initialization function.
	 * @return Zero on success, otherwise non-zero.
	 */
	int init_plugin(mocha_plugin_init_func_t init);
	mocha_plugin_factory_params fp_;
	///
	shared_library_ptr_t lib_;
	///
	mocha_plugin_deinit_func_t deinit_;
	///
	object_con_t objects_;
};
}

#endif

